package com.ludomancy.insane;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.BufferedImage;

import com.ludomancy.gamelib.ImageManipulation;
import com.ludomancy.gamelib.ImageStrip;
import com.ludomancy.gamelib.ResourceManager;

public class Earth
{
	public int[][] depth;
	public int[][] terrain;
	public int width;
	public int height;
	private ImageStrip tileset;
	private Image background;
	
	public static final int TERRAIN_DIRT = 1;
	public static final int TERRAIN_WATER = 2;
	public static final int TERRAIN_ROCK = 3;
	public static final int TERRAIN_GRASS = 4;
	
	private static final int TILE_DIRT_LOW = 1;
	private static final int TILE_DIRT_HIGH = 0;
	private static final int TILE_WATER = 2;
	private static final int TILE_ROCK = 3;
	private static final int TILE_GRASS = 4;
	
	public Earth()
	{
		// load map
		Image img = ResourceManager.getImage("map.png");
		width = img.getWidth(null);
		height = img.getHeight(null);
		background = ImageManipulation.createImage(width*3, height*3);
		BufferedImage bi = ImageManipulation.toBufferedImage(img);
		depth = new int[width][height];
		terrain = new int[width][height];
		for (int y = 0; y < height; y++)
		{
			for (int x = 0; x < width; x++)
			{
				int type = bi.getRGB(x, y) & 0x00FFFFFF;
				switch(type)
				{
					case 0x695012:
						depth[x][y] = 0;
						terrain[x][y] = TERRAIN_DIRT;
						break;
					case 0x42320D:
						depth[x][y] = 1;
						terrain[x][y] = TERRAIN_DIRT;
						break;
					case 0x005D8F:
						depth[x][y] = 1;
						terrain[x][y] = TERRAIN_WATER;						
						break;
					case 0x727678:
						depth[x][y] = 0;
						terrain[x][y] = TERRAIN_ROCK;
						break;
					case 0x0C941E:
						depth[x][y] = 0;
						terrain[x][y] = TERRAIN_GRASS;
						break;
					default:
						System.out.println("Fuck! tile: "+type);
						break;
				}
			}
		}
		tileset = new ImageStrip(ResourceManager.getImage("tiles.png"), Game.TILE_WIDTH, Game.TILE_HEIGHT);
		updateFloods();
		updateTiles();
	}
	
	public void updateFloods()
	{
		for (int y = 0; y < height; y++)
		{
			for (int x = 0; x < width; x++)
			{
				if(terrain[x][y] == TERRAIN_WATER)
				{
					flood(x, y, true);
				}
			}
		}
	}
	
	public Point toTile(Point pos)
	{
		return new Point(pos.x/3, pos.y/3);
	}
	
	private boolean isIn(int x, int y)
	{
		return x >= 0 && y >= 0 && x < width && y < height;
	}
	
	public void update()
	{
		for (int y = 0; y < height; y++)
		{
			for (int x = 0; x < width; x++)
			{
				if(terrain[x][y] == TERRAIN_GRASS)
				{
					//TODO: grow grass
				}
			}
		}
	}
	
	private void flood(int x, int y, boolean firstTime)
	{
		if(isIn(x,y))
		{
			if(isWaterFloodable(x,y) && (firstTime || terrain[x][y] == TERRAIN_DIRT))
			{
				setTerrain(x,y, TERRAIN_WATER);
				flood(x+1,y, false);
				flood(x-1,y, false);
				flood(x,y+1, false);
				flood(x,y-1, false);
				flood(x+1,y+1, false);
				flood(x-1,y-1, false);
				flood(x+1,y-1, false);
				flood(x-1,y+1, false);
			}
		}
	}
	
	private void setTerrain(int x, int y, int type)
	{
		terrain[x][y] = type;
		updateTile(x,y);
	}
	
	private void updateTiles()
	{
		for (int y = 0; y < height; y++)
		{
			for (int x = 0; x < width; x++)
			{
				updateTile(x,y);
			}
		}
	}
	
	private void updateTile(int x, int y)
	{
		int px = x * Game.TILE_WIDTH;
		int py = y * Game.TILE_WIDTH;
		
		int terrainT = terrain[x][y];
		int depthT   = depth[x][y];
		
		int tile = 0;
		
		switch(terrainT)
		{
			case TERRAIN_DIRT:
				tile = depthT > 0 ? TILE_DIRT_LOW : TILE_DIRT_HIGH;
				break;
			case TERRAIN_WATER:
				tile = TILE_WATER;
				break;
			case TERRAIN_GRASS:
				tile = TILE_GRASS;
				break;
			case TERRAIN_ROCK:
				tile = TILE_ROCK;
				break;
		}
		
		tileset.paint(background.getGraphics(), tile, px, py);		
	}
	
	private boolean isDiggable(int x, int y)
	{
		return (terrain[x][y] == TERRAIN_DIRT || terrain[x][y] == TERRAIN_GRASS) && depth[x][y] == 0; 
	}
	
	private boolean isWaterFloodable(int x, int y)
	{
		return depth[x][y] == 1;
	}
		
	public void paint(Graphics g)
	{
		g.drawImage(background, 0, 0, null);
	}
	
	private void dig(int x, int y)
	{
		if(depth[x][y] != 1)
		{
			depth[x][y] = 1;
			terrain[x][y] = TERRAIN_DIRT;
		}
	}

	public void dig(int x, int y, int radius)
	{
		if(depth[x][y] != 1)
		{
			internalDig(x,y,radius);
			updateFloods();
		}
	}
	
	private void internalDig(int x, int y, int radius)
	{
		if(radius > 0 && isIn(x, y) && isDiggable(x,y))
		{
			dig(x,y);
			updateTile(x,y);
			internalDig(x-1, y, radius-1);
			internalDig(x, y-1, radius-1);
			internalDig(x+1, y, radius-1);
			internalDig(x, y+1, radius-1);
			internalDig(x-1, y-1, radius-1);
			internalDig(x+1, y-1, radius-1);
			internalDig(x+1, y+1, radius-1);
			internalDig(x-1, y+1, radius-1);
		}		
	}

	public void flood(int x, int y)
	{
		flood(x,y,true);
	}
}
